package com.reactim.user.service.impl;

// import com.reactim.common.response.ResultCode;
// import com.reactim.common.util.IdGenerator;
import com.reactim.user.dto.UserLoginRequest;
import com.reactim.user.dto.UserRegisterRequest;
import com.reactim.user.dto.UserResponse;
import com.reactim.user.entity.User;
import com.reactim.user.repository.UserRepository;
import com.reactim.user.service.UserService;
import com.reactim.user.util.JwtUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 用户服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
    
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    private final JwtUtil jwtUtil;
    
    @Override
    @Transactional
    public Mono<UserResponse> register(UserRegisterRequest request) {
        return Mono.fromCallable(() -> {
            // 检查用户名是否已存在
            if (userRepository.existsByUsername(request.getUsername())) {
                throw new RuntimeException("用户名已存在");
            }
            
            // 检查手机号是否已存在
            if (request.getPhone() != null && userRepository.existsByPhone(request.getPhone())) {
                throw new RuntimeException("手机号已存在");
            }
            
            // 检查邮箱是否已存在
            if (request.getEmail() != null && userRepository.existsByEmail(request.getEmail())) {
                throw new RuntimeException("邮箱已存在");
            }
            
            // 创建用户
            User user = new User();
            user.setId(System.currentTimeMillis()); // 临时使用时间戳作为ID
            user.setUsername(request.getUsername());
            user.setNickname(request.getNickname());
            user.setPassword(encodePassword(request.getPassword())); // 暂时使用简单编码
            user.setPhone(request.getPhone());
            user.setEmail(request.getEmail());
            user.setAvatarUrl(request.getAvatarUrl());
            user.setStatus(User.UserStatus.NORMAL);
            user.setGender(User.Gender.UNKNOWN);
            
            User savedUser = userRepository.save(user);
            log.info("用户注册成功: {}", savedUser.getUsername());
            
            return convertToUserResponse(savedUser);
        }).subscribeOn(Schedulers.boundedElastic());
    }
    
    @Override
    public Mono<String> login(UserLoginRequest request) {
        return Mono.fromCallable(() -> {
            // 根据用户名查找用户
            User user = userRepository.findByUsername(request.getUsername())
                    .orElseThrow(() -> new RuntimeException("用户不存在"));
            
            // 检查用户状态
            if (user.getStatus() != User.UserStatus.NORMAL) {
                throw new RuntimeException("用户账号异常");
            }
            
            // 验证密码（暂时使用简单比较）
            if (!matchesPassword(request.getPassword(), user.getPassword())) {
                throw new RuntimeException("密码错误");
            }
            
            // 更新最后登录时间
            user.setLastLoginTime(LocalDateTime.now());
            userRepository.save(user);
            
            // 生成JWT Token
            String token = jwtUtil.generateToken(user.getId(), user.getUsername());
            log.info("用户登录成功: {}", user.getUsername());
            
            return token;
        }).subscribeOn(Schedulers.boundedElastic());
    }
    
    @Override
    public Mono<UserResponse> getUserById(Long userId) {
        return Mono.fromCallable(() -> {
            User user = userRepository.findById(userId)
                    .orElseThrow(() -> new RuntimeException("用户不存在"));
            return convertToUserResponse(user);
        }).subscribeOn(Schedulers.boundedElastic());
    }
    
    @Override
    public Mono<UserResponse> getUserByUsername(String username) {
        return Mono.fromCallable(() -> {
            User user = userRepository.findByUsername(username)
                    .orElseThrow(() -> new RuntimeException("用户不存在"));
            return convertToUserResponse(user);
        }).subscribeOn(Schedulers.boundedElastic());
    }
    
    @Override
    @Transactional
    public Mono<UserResponse> updateUser(Long userId, UserResponse userInfo) {
        return Mono.fromCallable(() -> {
            User user = userRepository.findById(userId)
                    .orElseThrow(() -> new RuntimeException("用户不存在"));
            
            // 更新用户信息
            if (userInfo.getNickname() != null) {
                user.setNickname(userInfo.getNickname());
            }
            if (userInfo.getAvatarUrl() != null) {
                user.setAvatarUrl(userInfo.getAvatarUrl());
            }
            if (userInfo.getSignature() != null) {
                user.setSignature(userInfo.getSignature());
            }
            if (userInfo.getGender() != null) {
                user.setGender(userInfo.getGender());
            }
            
            User savedUser = userRepository.save(user);
            log.info("用户信息更新成功: {}", savedUser.getUsername());
            
            return convertToUserResponse(savedUser);
        }).subscribeOn(Schedulers.boundedElastic());
    }
    
    @Override
    public Mono<List<UserResponse>> searchUsers(String keyword) {
        return Mono.fromCallable(() -> {
            List<User> users = userRepository.findByKeyword(keyword, User.UserStatus.NORMAL);
            return users.stream()
                    .map(this::convertToUserResponse)
                    .collect(Collectors.toList());
        }).subscribeOn(Schedulers.boundedElastic());
    }
    
    @Override
    public Mono<Boolean> existsByUsername(String username) {
        return Mono.fromCallable(() -> userRepository.existsByUsername(username))
                .subscribeOn(Schedulers.boundedElastic());
    }
    
    @Override
    public Mono<Boolean> validatePassword(String account, String password) {
        return Mono.fromCallable(() -> {
            User user = userRepository.findByAccount(account)
                    .orElse(null);
            if (user == null) {
                return false;
            }
            return matchesPassword(password, user.getPassword()); // 使用简单密码验证
        }).subscribeOn(Schedulers.boundedElastic());
    }
    
    @Override
    @Transactional
    public Mono<Void> updateLastLoginTime(Long userId) {
        return Mono.fromRunnable(() -> {
            userRepository.findById(userId).ifPresent(user -> {
                user.setLastLoginTime(LocalDateTime.now());
                userRepository.save(user);
            });
        }).subscribeOn(Schedulers.boundedElastic()).then();
    }
    
    @Override
    public boolean existsById(Long userId) {
        return userRepository.existsById(userId);
    }
    
    /**
     * 使用BCrypt编码密码
     */
    private String encodePassword(String rawPassword) {
        return passwordEncoder.encode(rawPassword);
    }
    
    /**
     * 验证密码（兼容旧的简单编码和新的BCrypt编码）
     */
    private boolean matchesPassword(String rawPassword, String encodedPassword) {
        // 检查是否是旧的简单编码格式
        if (encodedPassword.startsWith("encoded_")) {
            // 兼容旧的简单编码格式
            return encodedPassword.equals("encoded_" + rawPassword);
        } else {
            // 使用BCrypt验证
            return passwordEncoder.matches(rawPassword, encodedPassword);
        }
    }
    
    /**
     * 转换User实体为UserResponse DTO
     */
    private UserResponse convertToUserResponse(User user) {
        UserResponse response = new UserResponse();
        response.setId(user.getId());
        response.setUsername(user.getUsername());
        response.setNickname(user.getNickname());
        response.setAvatarUrl(user.getAvatarUrl());
        response.setPhone(user.getPhone());
        response.setEmail(user.getEmail());
        response.setSignature(user.getSignature());
        response.setGender(user.getGender());
        response.setLastLoginTime(user.getLastLoginTime());
        response.setCreatedAt(user.getCreatedAt());
        return response;
    }
}